package dca.sistemascontrole.handler;

import dca.sistemascontrole.dao.GraphicDataManager;
import dca.sistemascontrole.driver.GerenciadorComunicacao;
import dca.sistemascontrole.malhadecontrole.Clock;
import dca.sistemascontrole.malhadecontrole.Controlador;
import dca.sistemascontrole.malhadecontrole.ControladorCascata;
import dca.sistemascontrole.malhadecontrole.Observador;
import dca.sistemascontrole.malhadecontrole.MalhaAberta;
import dca.sistemascontrole.malhadecontrole.MalhaDeControle;
import dca.sistemascontrole.malhadecontrole.MalhaFechada;
import dca.sistemascontrole.malhadecontrole.SeguidorReferencia;
import dca.sistemascontrole.util.ControleConstantes;
import dca.sistemascontrole.util.XMLManager;
import dca.sistemascontrole.view.MainFrame;
import dca.sistemascontrole.view.PanelAnalises;
import dca.sistemascontrole.view.configuracao.DialogConfigurarPortas;
import dca.sistemascontrole.view.estimacaoestado.FrameEstadoEstimado;
import java.io.FileNotFoundException;
import java.io.IOException;
import javax.swing.JFileChooser;

/**
 *
 * @author Rafael
 */
public class HandlerMainFrame {

    private Clock clock;
    private String savePath;
    private MainFrame mainFrame;
    private Observador observador;
    private Controlador controlador;
    private PanelAnalises pnlAnalises;
    private MalhaDeControle malhaDeControle = new MalhaAberta();
    private GraphicDataManager graphicDataManager = new GraphicDataManager();
    private GerenciadorComunicacao gerenciadorComunicacao = new GerenciadorComunicacao();

    public HandlerMainFrame(MainFrame mainFrame, PanelAnalises panelAnalises) {
        clock = new Clock(this);
        this.mainFrame = mainFrame;
        this.pnlAnalises = panelAnalises;
    }

    public void setMalhaDeControle(MalhaDeControle malhaDeControle) {
        this.malhaDeControle = malhaDeControle;
    }

    public void setMalhaDeControle(int tipoControlador, float setPoint, float kp, float ki, float kd, float tw, float gama,
            boolean usarFiltroDerivativo, boolean usarFiltroAntiWindup) {
        if (tipoControlador == malhaDeControle.getTipo()) {
            ((MalhaFechada) malhaDeControle).setKd(kd);
            ((MalhaFechada) malhaDeControle).setKi(ki);
            ((MalhaFechada) malhaDeControle).setKp(kp);
            ((MalhaFechada) malhaDeControle).setTw(tw);
            ((MalhaFechada) malhaDeControle).setGama(gama);
            ((MalhaFechada) malhaDeControle).setSetpoint(setPoint);
            ((MalhaFechada) malhaDeControle).setUsarFiltroAntiWindup(usarFiltroAntiWindup);
            ((MalhaFechada) malhaDeControle).setUsarFiltroDerivativo(usarFiltroDerivativo);
        } else {
            malhaDeControle = MalhaFechada.criarMalhaFechada(tipoControlador, setPoint, kp, ki, kd, usarFiltroDerivativo, usarFiltroAntiWindup);
            ((MalhaFechada) malhaDeControle).setTw(tw);
            ((MalhaFechada) malhaDeControle).setGama(gama);
        }
        
        observador = new Observador(observador.getGanho1(), observador.getGanho2());
        FrameEstadoEstimado frameEstadoEstimado = FrameEstadoEstimado.getINSTANCE();
        frameEstadoEstimado.clear();
    }

    public void setMalhaDeControleCascata(int tipoControladorMestre, float setPoint, float kpMestre, float kiMestre, float kdMestre,
            int tipoControladorEscravo, float kpEscravo, float kiEscravo, float kdEscravo, float tw, float gama, boolean usarFiltroDerivativo,
            boolean usarFiltroAntiWindup) {

        if (MalhaDeControle.isMalhaCascata(malhaDeControle.getTipo())) {
            ((ControladorCascata) malhaDeControle).setKdMestre(kdMestre);
            ((ControladorCascata) malhaDeControle).setKiMestre(kiMestre);
            ((ControladorCascata) malhaDeControle).setKpMestre(kpMestre);
            ((ControladorCascata) malhaDeControle).setKdEscravo(kdEscravo);
            ((ControladorCascata) malhaDeControle).setKiEscravo(kiEscravo);
            ((ControladorCascata) malhaDeControle).setKpEscravo(kpEscravo);
            ((ControladorCascata) malhaDeControle).setTw(tw);
            ((ControladorCascata) malhaDeControle).setGama(gama);
            ((ControladorCascata) malhaDeControle).setSetpoint(setPoint);
            ((ControladorCascata) malhaDeControle).setUsarFiltroAntiWindup(usarFiltroAntiWindup);
            ((ControladorCascata) malhaDeControle).setUsarFiltroDerivativo(usarFiltroDerivativo);
        } else {
            MalhaFechada controladorMestre = MalhaFechada.criarMalhaFechada(tipoControladorMestre, setPoint,
                    kpMestre, kiMestre, kdMestre, false, false);
            MalhaFechada controladorEscravo = MalhaFechada.criarMalhaFechada(tipoControladorEscravo, setPoint,
                    kpEscravo, kiEscravo, kdEscravo, usarFiltroDerivativo, usarFiltroAntiWindup);

            malhaDeControle = new ControladorCascata(setPoint, controladorMestre, controladorEscravo);
            ((ControladorCascata) malhaDeControle).setTw(tw);
            ((ControladorCascata) malhaDeControle).setGama(gama);
        }
    }
    
    public void setSeguidorDeReferencia(double setpoint, double ganho1, double ganho2, double ganho3){
        if (malhaDeControle.getTipo() == MalhaDeControle.MALHA_SEGUIDOR_REFERENCIA) {
            ((SeguidorReferencia) malhaDeControle).setGanho1(ganho1);
            ((SeguidorReferencia) malhaDeControle).setGanho2(ganho2);
            ((SeguidorReferencia) malhaDeControle).setGanho3(ganho3);
            ((SeguidorReferencia) malhaDeControle).setSetpoint(setpoint);
        }else{
            malhaDeControle = new SeguidorReferencia(setpoint, ganho1, ganho2, ganho3);
        }
    }

    public void setObservador(float ganho1, float ganho2) {
        observador = new Observador(ganho1, ganho2);
    }

    public void interromper() {
        malhaDeControle = new MalhaAberta();
    }

    public void showDialogoConfiguração() {
        DialogConfigurarPortas dialogoConfigurarPortas = new DialogConfigurarPortas(mainFrame, true, gerenciadorComunicacao);
        dialogoConfigurarPortas.setVisible(true);
    }

    public synchronized void setVariaveisNivel(double nivelTanqueSuperior, double nivelTanqueInferior, 
            double setPoint, double erro, long t, double referencia) {
        mainFrame.setVariaveisNivel(nivelTanqueSuperior, nivelTanqueInferior, setPoint, erro, t, referencia);

        graphicDataManager.addTanqueInferior(nivelTanqueInferior, t);
        graphicDataManager.addTanqueSuperior(nivelTanqueSuperior, t);
        graphicDataManager.addReferencia(referencia, t);
        graphicDataManager.addSetpoint(setPoint, t);
        graphicDataManager.addErro(erro, t);

        pnlAnalises.calcularAnalises(setPoint, nivelTanqueSuperior, nivelTanqueInferior);
    }

    public synchronized void setVariaveisTensao(double uSaturado, double u, double ui, double up, double ud, long t) {
        mainFrame.setVariaveisTensao(uSaturado, u, ui, up, ud, t);

        graphicDataManager.addUSaturado(uSaturado, t);
        graphicDataManager.addU(u, t);
        graphicDataManager.addUi(ui, t);
        graphicDataManager.addUp(up, t);
        graphicDataManager.addUd(ud, t);
    }

    public void usarFiltroDerivativo(boolean usar) {
        if (malhaDeControle instanceof MalhaFechada) {
            ((MalhaFechada) malhaDeControle).setUsarFiltroDerivativo(usar);
        }
    }

    public void usarFiltroAntiWindup(boolean usar) {
        if (malhaDeControle instanceof MalhaFechada) {
            ((MalhaFechada) malhaDeControle).setUsarFiltroDerivativo(usar);
        }
    }

    public void saveGraphicData() throws FileNotFoundException, IOException {
        JFileChooser fileChooser = new JFileChooser(savePath);
        int option = fileChooser.showSaveDialog(mainFrame);

        if (option == JFileChooser.APPROVE_OPTION) {
            String absolutePath = fileChooser.getSelectedFile().getAbsolutePath();
            savePath = fileChooser.getSelectedFile().getParent();

            XMLManager.writeObject(graphicDataManager, absolutePath + "." + ControleConstantes.FILE_IDENTIFICADOR_DADOS);
        }
    }

    public void iniciarClock() {
        clock.start();
    }

    public void runControlador(long t) {
        if (controlador == null || controlador.isDone()) {
            controlador = new Controlador(malhaDeControle, this, gerenciadorComunicacao, observador, t);
            controlador.execute();
        }
    }

    public void clear() {
        graphicDataManager.clear();
    }
}
